Skip to content
This repository was archived by the owner on Jan 13, 2026. It is now read-only.

ITO-444: Implement Ito Words Tracker#451

Merged
fulltimemike merged 2 commits intodevfrom
ito-444
Nov 25, 2025
Merged

ITO-444: Implement Ito Words Tracker#451
fulltimemike merged 2 commits intodevfrom
ito-444

Conversation

@fulltimemike
Copy link
Collaborator

This uses client side data, which is unreliable. This is probably fine to do as is, but when we start enforcing a premium option, we will need accurate data. I have filed #448 , #449, and #450 as the series of issues necessary to get the words tracker to where we want it

@github-actions
Copy link

Resolves #444

@coderabbitai
Copy link

coderabbitai bot commented Nov 25, 2025

Walkthrough

This change introduces a new centralized utility module app/utils/userMetrics.ts that provides reusable functions for calculating engagement metrics from Interaction records, including weekly word counts, streaks, and average WPM. Components are refactored to use these utilities: SubscriptionStatusWidget now calculates weekly words internally, HomeContent replaces local statistics logic with the centralized calculateAllStats function, and the InteractionStats type now includes a weeklyWords field. Unused code is removed from PricingBillingSettingsContent. A minor formatting adjustment is applied to transcribeStreamV2Handler.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'ITO-444: Implement Ito Words Tracker' directly and clearly describes the main objective of the PR—implementing a words tracker feature—and relates to the primary changes across all modified files.
Description check ✅ Passed The description is related to the changeset, explaining the implementation approach (client-side data), acknowledging its limitations, and referencing follow-up issues for data accuracy improvements needed for premium enforcement.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ito-444

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc40198 and fe4281c.

📒 Files selected for processing (5)
  • app/components/home/SubscriptionStatusWidget.tsx (3 hunks)
  • app/components/home/contents/HomeContent.tsx (3 hunks)
  • app/components/home/contents/settings/PricingBillingSettingsContent.tsx (0 hunks)
  • app/utils/userMetrics.ts (1 hunks)
  • server/src/services/ito/transcribeStreamV2Handler.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • app/components/home/contents/settings/PricingBillingSettingsContent.tsx
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always prefer console commands over log commands. Use console.log instead of log.info

Files:

  • server/src/services/ito/transcribeStreamV2Handler.ts
  • app/components/home/SubscriptionStatusWidget.tsx
  • app/utils/userMetrics.ts
  • app/components/home/contents/HomeContent.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/always.mdc)

Never use empty catch statements

Files:

  • server/src/services/ito/transcribeStreamV2Handler.ts
  • app/components/home/SubscriptionStatusWidget.tsx
  • app/utils/userMetrics.ts
  • app/components/home/contents/HomeContent.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/code-conventions.mdc)

**/*.{ts,tsx}: Follow standard, idiomatic TypeScript coding practices for structure, naming, and types
Avoid adding comments unless they explain complex logic or non-obvious decisions; well-written, self-explanatory code is preferred
Do not add comments that merely restate what the code does
Rely on comprehensive tests to document the behavior and usage of code rather than extensive comments within the code itself
Use kebab-case when naming directories, TypeScript, and other files

**/*.{ts,tsx}: Prefer interfaces over types for object definitions
Use type for unions, intersections, and mapped types
NEVER use any or as any types or coercion
Leverage TypeScript's built-in utility types
Use generics for reusable type patterns
Use PascalCase for type names and interfaces
Use camelCase for variables and functions
Use UPPER_CASE for constants
Use descriptive names with auxiliary verbs (e.g., isLoading, hasError)
Prefix interfaces for React props with 'Props' (e.g., ButtonProps)
Keep type definitions close to where they're used
Export types and interfaces from dedicated type files when shared
Co-locate component props with their components
Use explicit return types for public functions
Use arrow functions for callbacks and methods
Implement proper error handling with custom error types
Use function overloads for complex type scenarios
Prefer async/await over Promises
Prefer function declarations over function expressions
Use readonly for immutable properties
Leverage discriminated unions for type safety
Use type guards for runtime type checking
Implement proper null checking
Avoid type assertions unless necessary
Handle Promise rejections properly

Files:

  • server/src/services/ito/transcribeStreamV2Handler.ts
  • app/components/home/SubscriptionStatusWidget.tsx
  • app/utils/userMetrics.ts
  • app/components/home/contents/HomeContent.tsx
server/**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

Backend code and database migrations should be organized in server/ using Bun

Files:

  • server/src/services/ito/transcribeStreamV2Handler.ts
{app,lib,server}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

{app,lib,server}/**/*.{ts,tsx,js,jsx}: Use ESLint to enforce code style and run bun run lint before submitting code
Always use console commands instead of log commands (e.g., console.log instead of log.info)

Files:

  • server/src/services/ito/transcribeStreamV2Handler.ts
  • app/components/home/SubscriptionStatusWidget.tsx
  • app/utils/userMetrics.ts
  • app/components/home/contents/HomeContent.tsx
{app,lib,server}/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Constants use SCREAMING_SNAKE_CASE naming convention

Files:

  • server/src/services/ito/transcribeStreamV2Handler.ts
  • app/components/home/SubscriptionStatusWidget.tsx
  • app/utils/userMetrics.ts
  • app/components/home/contents/HomeContent.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use kebab-case for files and directories
Do not use 'use client' or 'use server' statements in React components
Favor named exports for components
Ensure components are modular, reusable, and maintain a clear separation of concerns
Always split React components so there is only ever one per file
Keep logic as low as possible in React components
Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • app/components/home/SubscriptionStatusWidget.tsx
  • app/components/home/contents/HomeContent.tsx
app/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Electron renderer code should be organized in the app/ directory and use React + Tailwind

Files:

  • app/components/home/SubscriptionStatusWidget.tsx
  • app/utils/userMetrics.ts
  • app/components/home/contents/HomeContent.tsx
{app,lib}/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Prettier with 2-space indent for code formatting across TypeScript and React files

Files:

  • app/components/home/SubscriptionStatusWidget.tsx
  • app/utils/userMetrics.ts
  • app/components/home/contents/HomeContent.tsx
{app,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

{app,lib}/**/*.{ts,tsx}: Components and classes use PascalCase naming convention
Hooks and utility functions use camelCase naming convention

Files:

  • app/components/home/SubscriptionStatusWidget.tsx
  • app/utils/userMetrics.ts
  • app/components/home/contents/HomeContent.tsx
app/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Co-locate Tailwind styles with React components and reuse tokens via lib/constants

Files:

  • app/components/home/SubscriptionStatusWidget.tsx
  • app/components/home/contents/HomeContent.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: julgmz
Repo: heyito/ito PR: 446
File: app/components/home/HomeKit.tsx:236-236
Timestamp: 2025-11-24T21:51:44.018Z
Learning: In app/components/home/SubscriptionStatusWidget.tsx, the hardcoded default wordsUsed value (1000) is intentional as a temporary placeholder until a future feature implements real usage tracking.
📚 Learning: 2025-11-24T21:51:44.018Z
Learnt from: julgmz
Repo: heyito/ito PR: 446
File: app/components/home/HomeKit.tsx:236-236
Timestamp: 2025-11-24T21:51:44.018Z
Learning: In app/components/home/SubscriptionStatusWidget.tsx, the hardcoded default wordsUsed value (1000) is intentional as a temporary placeholder until a future feature implements real usage tracking.

Applied to files:

  • app/components/home/SubscriptionStatusWidget.tsx
🧬 Code graph analysis (2)
app/components/home/SubscriptionStatusWidget.tsx (3)
app/hooks/useBillingState.ts (1)
  • useBillingState (44-191)
app/store/useMainStore.ts (1)
  • useMainStore (49-68)
app/utils/userMetrics.ts (1)
  • calculateWeeklyWordCount (36-47)
app/components/home/contents/HomeContent.tsx (1)
app/utils/userMetrics.ts (1)
  • calculateAllStats (135-148)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run-tests / test
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (swift)
🔇 Additional comments (9)
server/src/services/ito/transcribeStreamV2Handler.ts (1)

312-315: LGTM!

Formatting-only change with no functional impact.

app/components/home/contents/HomeContent.tsx (1)

33-33: Clean refactoring to centralized utilities.

The migration to calculateAllStats from the new userMetrics module removes duplicate logic and improves maintainability. The empty dependency array is correct since calculateAllStats is a stable module import.

Note that weeklyWords is calculated but only used elsewhere (SubscriptionStatusWidget). Consider whether this component needs to calculate it if it's not displaying it.

Also applies to: 74-79, 103-110

app/utils/userMetrics.ts (5)

6-14: LGTM!

Correct implementation for getting Monday as the start of the week. The Sunday edge case (day=0 → diff=-6) is handled properly.


19-31: LGTM!

Clean word counting implementation with proper whitespace handling and empty string filtering. The weekly calculation correctly delegates to calculateTotalWords after filtering.

Also applies to: 36-47


52-83: Minor: WPM floors at 1 even for very slow speech.

Line 82 uses Math.max(1, wpm) which means the minimum displayed WPM is always 1, even if a user spoke very slowly. This appears intentional for UX purposes to avoid showing "0 words/minute".


135-148: LGTM!

Clean aggregation function with proper early return for empty arrays.


88-123: Clarify streak design and misleading comment.

The concern is valid: the current implementation returns 0 if the most recent activity is yesterday. The loop starts at i=0 comparing sortedDates[0] (most recent) against today; if yesterday is most recent, it immediately breaks and returns 0.

However, the inline comment "allowing for today or previous consecutive days" is misleading—it only allows consecutive days starting from today. No tests or documentation exist clarifying whether this is intentional design or an oversight.

Consider either:

  1. Confirming this is the desired behavior and clarifying the comment to "requires activity today as streak start"
  2. Implementing a grace period (if that's the actual requirement) to allow yesterday's activity to continue the streak until end of day
app/components/home/SubscriptionStatusWidget.tsx (2)

17-36: LGTM! Real usage tracking implemented as intended.

This replaces the hardcoded placeholder value (1000) with actual weekly word count tracking. The implementation correctly:

  • Uses the centralized calculateWeeklyWordCount utility
  • Subscribes to interaction-created for real-time updates
  • Properly cleans up the subscription on unmount

Based on learnings, the previous hardcoded value was intentional as a temporary placeholder until real tracking was implemented.


101-101: LGTM!

The usage percentage and display text now correctly use the dynamically loaded weeklyWords value.

Also applies to: 121-121

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Comment @coderabbitai help to get the list of available commands and usage tips.

@fulltimemike fulltimemike merged commit 5ca1681 into dev Nov 25, 2025
10 checks passed
@fulltimemike fulltimemike deleted the ito-444 branch November 26, 2025 15:54
@coderabbitai coderabbitai bot mentioned this pull request Dec 4, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants